package com.hmdp.service.impl;


import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hmdp.cache.RedisCacheClient;
import com.hmdp.dto.Result;
import com.hmdp.entity.Shop;
import com.hmdp.error.ErrorMsgHandler;
import com.hmdp.mapper.ShopMapper;
import com.hmdp.service.IShopService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.hmdp.utilObj.RedisData;
import com.hmdp.utils.SystemConstants;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.geo.Distance;
import org.springframework.data.geo.GeoResult;
import org.springframework.data.geo.GeoResults;
import org.springframework.data.redis.connection.RedisGeoCommands;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.domain.geo.GeoReference;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.time.temporal.TemporalUnit;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import static com.hmdp.utils.RedisConstants.*;
import static java.util.Collections.EMPTY_LIST;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 虎哥
 * @since 2021-12-22
 */
@Service
@RequiredArgsConstructor
public class ShopServiceImpl extends ServiceImpl<ShopMapper, Shop> implements IShopService {
    private final StringRedisTemplate stringRedisTemplate;
    private final RedisCacheClient cacheClient;

    @Override
    public Result queryById(Long id) {
        //缓存穿透逻辑

        //缓存击穿逻辑
        Shop shop = cacheClient.queryWithMutex(CACHE_SHOP_KEY,LOCK_SHOP_KEY,id,Shop.class,this::getById,CACHE_SHOP_TTL,TimeUnit.SECONDS,CACHE_NULL_TTL,TimeUnit.SECONDS);
        //Shop shop=cacheClient.queryWithLogicExpire(CACHE_SHOP_KEY,LOCK_SHOP_KEY,id,this::getById,Shop.class,CACHE_SHOP_TTL, ChronoUnit.SECONDS);
        if(shop==null)
        {
            return Result.fail(ErrorMsgHandler.getErrMsg("03",ShopServiceImpl.class));
        }
        return Result.ok(shop);
    }




    @Override
    public Result update(Shop shop) {
        Long id = shop.getId();
        if(id==null)
        {
            return Result.fail(ErrorMsgHandler.getErrMsg("04",ShopServiceImpl.class));
        }
        //1.更新数据库
        updateById(shop);
        //2.删除缓存
        stringRedisTemplate.delete(CACHE_SHOP_KEY+id);
        return Result.ok();
    }

    @Override
    public Result queryShopByType(Integer typeId, Integer current, Double x, Double y) {
        //判断是否需要根据坐标查询
        if(x==null||y==null){
            //不需要坐标查询,按数据库查询
            Page<Shop> page = query().eq("type_id", typeId)
                    .page(new Page<>(current, SystemConstants.DEFAULT_PAGE_SIZE));
            //返回数据
            return Result.ok(page.getRecords());
        }
        //计算分页参数---current页码
        int from=(current-1)*SystemConstants.DEFAULT_PAGE_SIZE;
        int end=current*SystemConstants.DEFAULT_PAGE_SIZE;
        //查询redis,按照距离排序,分页。
        String key=SHOP_GEO_KEY+typeId;
        //GEOSEARCH key BYLONLAT x y BYRADIUS 10 WITHDISTANCE
        GeoResults<RedisGeoCommands.GeoLocation<String>> list = stringRedisTemplate.opsForGeo()
                .search(key,
                        //指定中心点--经纬度
                        GeoReference.fromCoordinate(x, y),
                        //搜索半径--默认单位为米
                        new Distance(5000),
                        //结果里面带上距离
                        RedisGeoCommands.GeoSearchCommandArgs.newGeoSearchArgs().includeDistance()
                                //从第一条开始到end条记录后结束--我们需要手动剪裁出from部分
                                .limit(end));
         //解析出id
        if (list == null) {
           return Result.ok(EMPTY_LIST);
        }
        List<GeoResult<RedisGeoCommands.GeoLocation<String>>> content = list.getContent();
        if(content.size()<from){
            return  Result.ok(EMPTY_LIST);
        }
        //截取from~end部分
        ArrayList<Object> ids = new ArrayList<>(content.size());
        HashMap<Object, Distance> distanceMap = new HashMap<>(content.size());
        content.stream().skip(from).forEach(res->{
            //获取店铺id
            String shopIdStr = res.getContent().getName();
            ids.add(Long.valueOf(shopIdStr));
            //获取距离
            Distance distance = res.getDistance();
            distanceMap.put(shopIdStr,distance);
        });
        //根据id查询shop
        String idStr = StrUtil.join(",", ids);
        List<Shop> shops = query().in("id", ids).last("ORDER BY FIELD(id," + idStr + ")").list();
        for (Shop shop : shops) {
            shop.setDistance(distanceMap.get(shop.getId().toString()).getValue());
        }
        return Result.ok(shops);
    }
}
